﻿package code {
	// Main document class that generates the snowflakes.
	import flash.display.Sprite;
	import flash.utils.*;
	import flash.events.*;
	import flash.system.*;
	import fl.motion.Color;
	
	public class Generator extends Sprite {
		
		var previousTime:int;
		var flakeMove, makeFlakes:Boolean; //Should the flake be moving
		var snowFlakeList:Array;	  	 // the array of snowflakes
		var buttonLayer, snowFlakeLayer:Sprite;	 // button layer
		
		const AMOUNT_TO_MAKE:int = 50;   // amount of snowflakes to make an initation
		
		// constants for the different randoms
		const SIZE_RANDOM:Number = 2;	 
		const COLOR_RANDOM:Number = 0xFFFFFF;
		const ROTATION_RANDOM:Number = 2 * Math.PI;
		const LENGTH_RANDOM:Number = 2000;
		const SPEED_RANDOM:Number = 50;
		
		
		public function Generator() {
			previousTime = 0;
			snowFlakeList = new Array();
			buttonLayer = new Sprite();
			snowFlakeLayer = new Sprite();
			
			generateSnowflakes(); 		// generates the initial group of snowflakes
			drawFlakes(); // draws the current flakes to screen
			flakeMove = true;
			play_Btn.addEventListener(MouseEvent.CLICK, doPlay);
			pause_Btn.addEventListener(MouseEvent.CLICK, pauseFlake); //Begin listening for Pause Button
			reset_Btn.addEventListener(MouseEvent.CLICK, reset);
			add_Btn.addEventListener(MouseEvent.CLICK, addMore);
			addEventListener(Event.ENTER_FRAME, update);
			
			init();  // initializes the layers
		}
		
		public function init(){
			buttonLayer.addChild(play_Btn);
			buttonLayer.addChild(pause_Btn);
			buttonLayer.addChild(reset_Btn);
			buttonLayer.addChild(add_Btn);
			buttonLayer.addChild(rateBox);
			buttonLayer.addChild(memoryBox);
			
			addSnowFlakeChildren();		// adds snowflakes to the stage
			
			addChild(snowFlakeLayer);
			addChild(buttonLayer);
		}
		
		// the initial snowflake generator
		public function generateSnowflakes():void{
			for(var i:int = 0; i < AMOUNT_TO_MAKE; i++){
				addSnowFlakes();
			}
		}
		
		// drwas all the snowflakes in the list
		public function drawFlakes():void{
			for each(var s:Snowflake in snowFlakeList){
				if(s != null)
					s.drawFlake();
			}
		}
		
		//Create and begin moving flakes
		public function doPlay(e:Event):void
		{
			flakeMove = true; //Restart flake movement
		}
		
		//Stop the flakes from moving
		public function pauseFlake(e:Event):void
		{			
			if(flakeMove == false)
			{
				flakeMove = true;
			}
			else
			{
				flakeMove = false;
			}
		}
		
		// resets the snowflakes
		public function reset(e:Event):void
		{
			for each(var s:Snowflake in snowFlakeList){
				snowFlakeLayer.removeChild(s);
			}
			snowFlakeList = new Array();
			
			generateSnowflakes();
			addSnowFlakeChildren();
			drawFlakes();
		}
		
		// adds more snowflakes
		public function addMore(e:Event):void{
			var newSnowFlake = addSnowFlakes();  // gets the new snowflake from the method
			snowFlakeLayer.addChild(newSnowFlake);	// adds it to the snowFlake layer
			newSnowFlake.drawFlake();	// draws it
		}
		
		// updates the time and flake movement
		public function update(e:Event):void
		{
			// updates the time
			var currentTime = getTimer();
			var timeChange = currentTime - previousTime;
			previousTime = currentTime;
			
			rateBox.amount.text = (1000/(timeChange)).toString(); // updates the framerate box
			memoryBox.amount.text = System.totalMemory.toString(); // updates the memory box
			
			if(flakeMove == true) //Only move if flakes should be moving
			{
				timeChange /= 1000; // to smooth everything
				moveFlakes(timeChange);
			}		
		}
		
		// moves the flakes down
		public function moveFlakes(timeChange:Number):void{
			for each(var s:Snowflake in snowFlakeList){
				if(s.y > stage.stageHeight){
					s.y = -300;  // sets at a constant value in the sky
				}
				else{
					s.y += s.flakeSpeed * timeChange;   // adjusts the location based on how much time has passed
				}

			}
		}
		
		// method that creates a snowflake and adds it to the snowFlakeList
		public function addSnowFlakes():Snowflake{
			var tempSnowflake:Snowflake;	// variable to hold the initial created snowflake
			var tempFlake2:Snowflake;		// variable to start the derivative snowflakes from
			var polygon:Polygon;			// variable to create the base polygon
			var localFlakeList:Array;		// the local flake list
			
			localFlakeList = new Array();			// resets the local flake list array
				
			var initPolySides:int = Math.random() * 10 + 3;	// makes sure the base geometry has at least three sides and can have up to 13

			polygon = new Polygon(initPolySides, new Vertex(100, 100));  // creates a new base polygon
			var xVal:Number = Math.random() * stage.stageWidth;			 // generates random information for each snowflake
			var yVal:Number = Math.random() * stage.stageHeight;
			var size:Number = Math.random() * SIZE_RANDOM;
			var colorVal:Number = Math.random() * COLOR_RANDOM;
			var rot:Number = Math.random() * ROTATION_RANDOM;
			var maxLength:Number = Math.random() * LENGTH_RANDOM;
			var speed:Number = Math.random() * SPEED_RANDOM + 5;
			tempSnowflake = new Snowflake(xVal, yVal, size, rot, colorVal, maxLength, speed);
			
			for each(var v:Vertex in polygon.vertices){
				tempSnowflake.vertices.push(v);		// pushes the vertices from the base polygon for the base of the snowflake
			}
			
			var newFlake = tempSnowflake.create();  // sends in the local list so that we can get the final flake back
			
			if(newFlake != null)  // for some reason some flakes are null
				snowFlakeList.push(newFlake); // adds the resultant flake to the overall flake list 
				
			return newFlake;
		}
		
		// adds back the children
		public function addSnowFlakeChildren():void{
			for each(var s:Snowflake in snowFlakeList){
				snowFlakeLayer.addChild(s);
			}
		}
		
	}
	
}
